import { useEffect, useMemo, useRef, useState } from 'react';
import { View, Canvas, Text } from '@tarojs/components';
import Taro from '@tarojs/taro';
import './index.scss';

export type ChannelStat = {
  resourceName?: string;
  customerCount?: number;
  orderCount?: number;
  totalPrice?: number;
};

interface DonutCompareProps {
  data: ChannelStat[];
  size?: number; // diameter in px
  ringWidth?: number; // stroke thickness
  gapAngle?: number; // degrees between segments to visually separate
  colors?: string[]; // color palette for channels
}

const DEFAULT_COLORS = [
  '#0A7AFF',
  '#34C759',
  '#FF9500',
  '#5856D6',
  '#FF3B30',
  '#FFCC00',
  '#5AC8FA',
  '#8E8E93',
  '#007AFF',
  '#FF2D55',
];

const METRICS: Array<{
  key: keyof Pick<ChannelStat, 'customerCount' | 'totalPrice' | 'orderCount'>;
  label: string;
  id: string;
}> = [
  { key: 'customerCount', label: '客资', id: 'customer' },
  { key: 'totalPrice', label: '成交额', id: 'amount' },
  { key: 'orderCount', label: '订单数', id: 'orders' },
];

export default function DonutCompare({
  data,
  size = 108,
  ringWidth = 10,
  gapAngle = 2,
  colors = DEFAULT_COLORS,
}: DonutCompareProps) {
  const uidRef = useRef(
    `donut-${Date.now().toString(36)}-${Math.random()
      .toString(36)
      .slice(2, 8)}`,
  );

  const [visibilityState, setVisibilityState] = useState<boolean[]>(() =>
    (data ?? []).map(() => true),
  );

  useEffect(() => {
    // Reset visibility when data length changes
    setVisibilityState((prev) => {
      const next = (data ?? []).map((_, idx) => prev[idx] ?? true);
      return next;
    });
  }, [data]);

  // const visibilityState = visibilityState;

  const totals = useMemo(() => {
    const obj: Record<string, number> = {};
    METRICS.forEach((m) => {
      obj[m.key] = (data ?? []).reduce((sum, d, idx) => {
        if (!visibilityState[idx]) return sum;
        return sum + (d[m.key] || 0);
      }, 0);
    });
    return obj as Record<'customerCount' | 'totalPrice' | 'orderCount', number>;
  }, [data, visibilityState]);

  const getCanvasId = (metricId: string) => `${uidRef.current}-${metricId}`;

  useEffect(() => {
    const drawWith2D = (
      ctx: CanvasRenderingContext2D,
      metricKey: keyof Pick<
        ChannelStat,
        'customerCount' | 'totalPrice' | 'orderCount'
      >,
      label: string,
    ) => {
      const width = size;
      const height = size;
      const centerX = width / 2;
      const centerY = height / 2;
      const radius = Math.max(1, (size - ringWidth) / 2);

      // clear
      ctx.clearRect(0, 0, width, height);

      // background ring
      ctx.lineCap = 'round';
      ctx.lineWidth = ringWidth;
      ctx.strokeStyle = '#F1F2F5';
      ctx.beginPath();
      ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
      ctx.stroke();

      const total = totals[metricKey] || 0;
      if (total > 0) {
        const startBase = -Math.PI / 2;
        const gap = (Math.PI / 180) * Math.max(0, gapAngle);
        let accAngle = startBase;
        data.forEach((item, index) => {
          if (!visibilityState[index]) return;
          const value = item?.[metricKey] || 0;
          if (value <= 0) return;
          const percent = value / total;
          const sweep = Math.max(0, percent * Math.PI * 2);
          const segStart = accAngle + gap / 2;
          const segEnd = accAngle + sweep - gap / 2;
          if (segEnd > segStart) {
            ctx.strokeStyle = colors[index % colors.length];
            ctx.beginPath();
            ctx.arc(centerX, centerY, radius, segStart, segEnd, false);
            ctx.stroke();
          }
          accAngle += sweep;
        });
      }

      // center text
      ctx.fillStyle = '#7C7C7C';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.font =
        '12px system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial';
      ctx.fillText(label, centerX, centerY);
    };

    const drawWithLegacy = (
      ctx: Taro.CanvasContext,
      metricKey: keyof Pick<
        ChannelStat,
        'customerCount' | 'totalPrice' | 'orderCount'
      >,
      label: string,
    ) => {
      const dpr = 1;
      const width = size * dpr;
      const height = size * dpr;
      const centerX = width / 2;
      const centerY = height / 2;
      const radius = Math.max(1, (size - ringWidth) / 2) * dpr;

      ctx.clearRect(0, 0, width, height);
      ctx.setLineCap('round');
      ctx.setLineWidth(ringWidth);
      ctx.setStrokeStyle('#F1F2F5');
      ctx.beginPath();
      ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
      ctx.stroke();

      const total = totals[metricKey] || 0;
      if (total > 0) {
        const startBase = -Math.PI / 2;
        const gap = (Math.PI / 180) * Math.max(0, gapAngle);
        let accAngle = startBase;
        data.forEach((item, index) => {
          if (!visibilityState[index]) return;
          const value = item?.[metricKey] || 0;
          if (value <= 0) return;
          const percent = value / total;
          const sweep = Math.max(0, percent * Math.PI * 2);
          const segStart = accAngle + gap / 2;
          const segEnd = accAngle + sweep - gap / 2;
          if (segEnd > segStart) {
            ctx.setStrokeStyle(colors[index % colors.length]);
            ctx.beginPath();
            ctx.arc(centerX, centerY, radius, segStart, segEnd, false);
            ctx.stroke();
          }
          accAngle += sweep;
        });
      }

      ctx.setFillStyle('#7C7C7C');
      ctx.setFontSize(12);
      ctx.setTextAlign('center');
      ctx.setTextBaseline('middle');
      ctx.fillText(label, centerX, centerY);

      ctx.draw();
    };

    METRICS.forEach(({ key, id, label }) => {
      const canvasId = getCanvasId(id);
      // Try 2D first
      Taro.createSelectorQuery()
        .select(`#${canvasId}`)
        .fields({ node: true, size: true } as any)
        .exec((res) => {
          const node = res?.[0]?.node as any;
          if (node && typeof node.getContext === 'function') {
            const canvas = node as HTMLCanvasElement;
            const dpr = Taro.getSystemInfoSync()?.pixelRatio || 1;
            canvas.width = size * dpr;
            canvas.height = size * dpr;
            // Some environments (e.g., WeChat 2D canvas) do not expose style
            const anyCanvas: any = canvas as any;
            if (anyCanvas && anyCanvas.style) {
              anyCanvas.style.width = `${size}px`;
              anyCanvas.style.height = `${size}px`;
            }
            const ctx2d = canvas.getContext('2d');
            if (ctx2d) {
              ctx2d.scale(dpr, dpr);
              drawWith2D(ctx2d, key, label);
              return;
            }
          }
          // Fallback to legacy context
          const legacy = Taro.createCanvasContext(canvasId);
          drawWithLegacy(legacy as any, key, label);
        });
    });
  }, [data, size, ringWidth, gapAngle, colors, totals, visibilityState]);

  const toggleLegend = (index: number) => {
    const apply = (current: boolean[]) => {
      const next = [...current];
      next[index] = !next[index];
      if (next.every((v) => !v)) {
        next[index] = true;
      }
      return next;
    };

    setVisibilityState((prev) => apply(prev));
  };

  return (
    <View className="donut-compare">
      <View className="legend">
        {data?.map((item, idx) => (
          <View
            key={`${uidRef.current}-legend-${idx}`}
            className={`legend-item${visibilityState[idx] ? '' : ' disabled'}`}
            onClick={() => toggleLegend(idx)}
          >
            <View
              className="dot"
              style={{ background: colors[idx % colors.length] }}
            />
            <Text>{item?.resourceName || '未知渠道'}</Text>
          </View>
        ))}
      </View>

      <View className="donut-row">
        {METRICS.map(({ id }) => (
          <View key={id} className="donut-cell" style={{ width: `${size}px` }}>
            <Canvas
              type="2d"
              id={getCanvasId(id)}
              canvasId={getCanvasId(id)}
              style={{
                width: `${size}px`,
                height: `${size}px`,
                display: 'block',
              }}
              width={`${size}`}
              height={`${size}`}
            />
          </View>
        ))}
      </View>
    </View>
  );
}
